<?php

namespace app\common\model;

use Exception;
use think\Collection;
use think\facade\Cache;
use think\facade\Db;

class Module extends CommonBase
{
    private const _CACHE_KEY = '%s_modules';

    private const _CREATE_MAIN_TABLE_SQL = <<<str
CREATE TABLE `%sarticle_%s` (  
	`category_id` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '栏目ID',  
	`id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,  
	`title` varchar(255)  NOT NULL DEFAULT ''  COMMENT '标题',  
	`meta_title` varchar(255)  NOT NULL DEFAULT ''  COMMENT 'seo标题',  
	`meta_description` varchar(255)  NOT NULL DEFAULT '' COMMENT 'seo描述',  
	`meta_keyword` varchar(255)  NOT NULL DEFAULT ''  COMMENT 'seo关键字',  
	`status` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '状态 1启用 2禁用',  
	`sort` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '排序',  
	`image` varchar(255)  NOT NULL DEFAULT '' COMMENT '图片',  
	`hit` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '访问次数',  
	`created_at` datetime DEFAULT NULL COMMENT '创建时间',  
	`updated_at` datetime DEFAULT NULL COMMENT '更新时间',  
	`is_delete` tinyint(3) unsigned NOT NULL DEFAULT 0 COMMENT '1未删除 2已删除',  
	index key_category_id(`category_id`) 
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='%s'
str;

    private const _CREATE_FLAG_TABLE_SQL = <<<str
CREATE TABLE `%sarticle_%s_flag` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `aid` int unsigned NOT NULL DEFAULT '0' COMMENT '文档ID',
  `flag_id` int unsigned NOT NULL DEFAULT '0' COMMENT 'flag ID',
  `is_delete` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '1未删除 2已删除',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `key_aid` (`aid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='%s';
str;

    private const _CREATE_IMAGE_TABLE_SQL = <<<str
CREATE TABLE `%sarticle_%s_image` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `aid` int unsigned NOT NULL DEFAULT '0' COMMENT '文档ID',
  `attribute_value_id` int unsigned NOT NULL DEFAULT '0' COMMENT '属性值ID',
  `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '标题',
  `image` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '图片',
  `sort` int NOT NULL DEFAULT '0' COMMENT '排序',
  `is_delete` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '1未删除 2已删除',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `key_aid` (`aid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='%s';
str;

    private const _CREATE_ATTRIBUTE_TABLE_SQL = <<<str
CREATE TABLE `%sarticle_%s_relation_attribute` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `aid` int unsigned NOT NULL DEFAULT '0' COMMENT '文档ID',
  `attribute_id` int unsigned NOT NULL DEFAULT '0' COMMENT '属性ID',
  `attribute_value_id` int unsigned NOT NULL DEFAULT '0' COMMENT '属性值ID',
  `is_delete` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '1未删除 2已删除',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `key_aid_attribute_id_attribute_value_id` (`aid`,`attribute_id`,`attribute_value_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='%s';
str;

    private const _CREATE_TEXT_TABLE_SQL = <<<str
CREATE TABLE `%sarticle_%s_text` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `aid` int unsigned NOT NULL DEFAULT '0' COMMENT '文档ID',
  `field_id` int unsigned NOT NULL DEFAULT '0' COMMENT '字段ID',
  `field_value` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT '字段值',
  `is_delete` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '1未删除 2已删除',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `key_field_id` (`field_id`) USING BTREE,
  KEY `key_aid` (`aid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='%s';
str;

    private const _CREATE_VARCHAR_TABLE_SQL = <<<str
CREATE TABLE `%sarticle_%s_varchar` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `aid` int unsigned NOT NULL DEFAULT '0' COMMENT '文档ID',
  `field_id` int unsigned NOT NULL DEFAULT '0' COMMENT '字段ID',
  `field_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '字段值',
  `is_delete` int unsigned NOT NULL DEFAULT '0' COMMENT '1未删除 2已删除',
  `created_at` datetime DEFAULT NULL COMMENT '创建时间',
  `updated_at` datetime DEFAULT NULL COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `key_field_id` (`field_id`) USING BTREE,
  KEY `key_aid` (`aid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='%s';
str;

    private const _DROP_TABLE_SQL = "DROP TABLE IF EXISTS `%s`";

    public function __construct(array $data = [], string $connection = 'mysql')
    {
        parent::__construct($data);
        $this->connection = $connection;
    }

    public function getAllModule(array $where = []): array
    {
        $cacheKey = sprintf(self::_CACHE_KEY, $this->connection);
        $modules  = Cache::get($cacheKey);
        if (empty($modules)) {
            $modules = $this->where(['is_delete' => config('status.mysql.table_normal')])->select()->toArray();
            Cache::set($cacheKey, $modules,self::CACHE_EXPIRE_TIME);
        }

        $res = [];
        foreach ($modules as $module) {
            $flag = true;
            foreach ($where as $key => $value) {
                if (is_array($value) && count($value) == 3 && $value[1] == 'in' && is_array($value[2])) {
                    if (!in_array($module[$value[0]], $value[2])) {
                        $flag = false;
                        break;
                    }
                } else if ($module[$key] != $value) {
                    $flag = false;
                    break;
                }
            }

            if ($flag) {
                $res[$module['id']] = $module;
            }
        }

        return $res;
    }

    public function getModuleList(int $page = 1, int $limit = 10, array $where = []): Collection
    {
        $where['is_delete'] = config('status.mysql.table_normal');
        $offset             = ($page - 1) * $limit;
        return $this->where($where)->limit($offset, $limit)->select();
    }

    public function getModuleCount(array $where = []): int
    {
        $where['is_delete'] = config('status.mysql.table_normal');
        return $this->where($where)->count();
    }

    public function findModuleByCode(string $code)
    {
        return $this->where(['code' => $code, 'is_delete' => config('status.mysql.table_normal')])->find();
    }

    public function findModuleById(int $id)
    {
        $modules = $this->getAllModule();
        return $modules[$id] ?? [];
    }

    public function getAllModuleByIds($ids)
    {
        return $this->where([
            ['id', 'in', $ids],
            'is_delete' => config('status.mysql.table_normal'),
        ])->select();
    }

    /**
     * @throws Exception
     */
    public function addModule(array $data): bool
    {

        $data['is_delete'] = config('status.mysql.table_normal');
        try {
            $this->startTrans();
            $moduleId = 0;
            $row      = $this->where(['is_delete' => config('status.mysql.table_delete'), 'code' => $data['code']])->find();
            if (!empty($row)) {
                $existModule        = $row->toArray();
                $data['created_at'] = date('Y-m-d H:i:s');
                $data['updated_at'] = date('Y-m-d H:i:s');

                $this->where(['id' => $existModule['id']])->save(array_merge($existModule, $data));
                $moduleId = $existModule['id'];
            } else {
                $this->save($data);
                $moduleId = $this->getLastInsID();
            }

            $status = config('status.mysql.table_normal');
            $fields = [
                ['name' => '标题', 'code' => 'title', 'field_type' => 'input', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_REQUIRE, 'show_list' => self::FIELD_IS_SHOW_LIST, 'sort' => 1],
                ['name' => 'seo标题', 'code' => 'meta_title', 'field_type' => 'textarea', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_NOT_REQUIRE, 'show_list' => self::FIELD_IS_HIDDEN_LIST, 'sort' => 2],
                ['name' => 'seo描述', 'code' => 'meta_description', 'field_type' => 'textarea', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_NOT_REQUIRE, 'show_list' => self::FIELD_IS_HIDDEN_LIST, 'sort' => 3],
                ['name' => 'seo关键词', 'code' => 'meta_keyword', 'field_type' => 'textarea', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_NOT_REQUIRE, 'show_list' => self::FIELD_IS_HIDDEN_LIST, 'sort' => 4],
                ['name' => '状态', 'code' => 'status', 'field_type' => 'radio', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_REQUIRE, 'show_list' => self::FIELD_IS_HIDDEN_LIST, 'sort' => 5],
                ['name' => '排序', 'code' => 'sort', 'field_type' => 'input', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_NOT_REQUIRE, 'show_list' => self::FIELD_IS_HIDDEN_LIST, 'sort' => 6],
                ['name' => '图片', 'code' => 'image', 'field_type' => 'image', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_NOT_REQUIRE, 'show_list' => self::FIELD_IS_SHOW_LIST, 'sort' => 7],
                ['name' => '访问次数', 'code' => 'hit', 'field_type' => 'input', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_NOT_REQUIRE, 'show_list' => self::FIELD_IS_SHOW_LIST, 'sort' => 8],
                ['name' => '创建时间', 'code' => 'created_at', 'field_type' => 'datetime', 'status' => $status, 'is_system' => self::FIELD_IS_SYSTEM, 'is_require' => self::FIELD_IS_NOT_REQUIRE, 'show_list' => self::FIELD_IS_SHOW_LIST, 'sort' => 9],
                ['name' => '内容', 'code' => 'content', 'field_type' => 'editor', 'status' => $status, 'is_system' => self::FIELD_IS_CUSTOMER, 'is_require' => self::FIELD_IS_NOT_REQUIRE, 'show_list' => self::FIELD_IS_HIDDEN_LIST, 'sort' => 10],
            ];
            foreach ($fields as $field) {
                $insertData = array_merge(
                    $field,
                    [
                        'module_id'  => $moduleId,
                        'is_delete'  => config('status.mysql.table_normal'),
                        'created_at' => date('Y-m-d H:i:s'),
                        'updated_at' => date('Y-m-d H:i:s'),
                    ]);

                $row = $this->name('field')->where(['is_delete' => config('status.mysql.table_delete'), 'module_id' => $moduleId, 'code' => $field['code']])->find();
                if (!empty($row)) {
                    $existModuleField = $row->toArray();
                    $this->name('field')->where(['id' => $existModuleField['id']])->save(
                        array_merge($existModuleField, $insertData)
                    );

                    continue;
                }

                $this->name('field')->insert($insertData);
            }

            $this->commit();
            Cache::delete(sprintf(self::_CACHE_KEY, $this->connection));
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw  new Exception($e->getMessage());
        }
    }

    public function updateModule(int $id, array $data): bool
    {
        $data['updated_at'] = date('Y-m-d H:i:s');
        return (boolean)$this->where(['id' => $id])->save($data) && Cache::delete(sprintf(self::_CACHE_KEY, $this->connection));;
    }

    /**
     * @throws Exception
     */
    public function deleteModule(int $id): bool
    {
        try {
            $this->startTrans();
            $this->where(['id' => $id])->save(['is_delete' => config('status.mysql.table_delete')]);
            $this->name('field')->where(['module_id' => $id])->save(['is_delete' => config('status.mysql.table_delete')]);

            $this->commit();
            Cache::delete(sprintf(self::_CACHE_KEY, $this->connection));
            return true;
        } catch (Exception $e) {
            $this->rollback();
            throw new Exception($e->getMessage());
        }
    }

    public function createTable(array $data): bool
    {
        $tables = [
            self::_CREATE_MAIN_TABLE_SQL,
            self::_CREATE_FLAG_TABLE_SQL,
            self::_CREATE_IMAGE_TABLE_SQL,
            self::_CREATE_ATTRIBUTE_TABLE_SQL,
            self::_CREATE_TEXT_TABLE_SQL,
            self::_CREATE_VARCHAR_TABLE_SQL,
        ];

        foreach ($tables as $tableSql) {
            $sql = sprintf($tableSql, config('database.connections.' . $this->connection . '.prefix'), $data['code'], $data['name']);
            Db::connect($this->connection)->execute($sql);
        }

        return true;
    }

    public function dropTable(array $data): bool
    {
        $tables = [
            "%sarticle_%s",
            "%sarticle_%s_flag",
            "%sarticle_%s_image",
            "%sarticle_%s_relation_attribute",
            "%sarticle_%s_text",
            "%sarticle_%s_varchar",
        ];

        foreach ($tables as $table) {
            $sql = sprintf(self::_DROP_TABLE_SQL, sprintf($table, config('database.connections.' . $this->connection . '.prefix'), $data['code']));
            Db::connect($this->connection)->execute($sql);
        }

        return true;
    }

    public function clearModuleCache(): bool
    {
        return Cache::delete(sprintf(self::_CACHE_KEY, $this->connection));
    }
}
